package server

import (
	"dag2.0/gat1400-proxy/cache"
	"dag2.0/gat1400-proxy/context"
	"dag2.0/gat1400-proxy/logger"
	"dag2.0/gat1400-proxy/model"
	"dag2.0/gat1400-proxy/util/times"
	"fmt"
	"math"
	"time"
)

const (
	WEIGHT_RESORECE    = 0.6 //设备资源数量
	WEIGHT_DATARATE    = 1.0 //数据速率
	WEIGHT_ALLOCATENUM = 0.4 //已分配次数

	DATA_RATE_SIZE_500_KEY     = "coefficient-data-rate.size500"
	DATA_RATE_SIZE_400_KEY     = "coefficient-data-rate.size400"
	DATA_RATE_SIZE_300_KEY     = "coefficient-data-rate.size300"
	DATA_RATE_SIZE_100_KEY     = "coefficient-data-rate.size100"
	DATA_RATE_SIZE_10_100_KEY  = "coefficient-data-rate.size10-100"
	DATA_RATE_SIZE_0_10_KEY    = "coefficient-data-rate.size0-10"
	COEFFICIENT_NETWORK_KEY    = "coefficient-network"
	INTERVAL_KEEPALIVE_TIME    = 10
	COEFFICIENT_ALLOCATE       = 6 * 20
	COEFFICIENT_KEEPALIVE      = 4
	COEFFICIENT_NETWORK        = 1024 * 1024
	COEFFICIENT_TPS_DATA500    = 160
	COEFFICIENT_TPS_DATA400    = 180
	COEFFICIENT_TPS_DATA300    = 200
	COEFFICIENT_TPS_DATA100    = 220
	COEFFICIENT_TPS_DATA10_100 = 400
	COEFFICIENT_TPS_DATA0_10   = 8000
	KEEPALIVE_TIMEOUT          = 30
)

func CheckKeepaliveSession() {
	go func() {
		for {
			time.Sleep(time.Second * time.Duration(INTERVAL_KEEPALIVE_TIME))
			delViewIds := make([]string, 0)
			cache.GetIns().GatServerInfos.Range(func(key string, value interface{}) bool {
				if _, ok := value.(*cache.GatServerInfoViewMap); !ok {
					logger.LOG_ERROR(fmt.Sprintf("类型错误,需要【*model.gatServerInfoViewMaps】类型，类型为%T", value))
					return false
				}
				gatServerInfoMap := value.(*cache.GatServerInfoViewMap)
				var timeOutKeys = make([]string, 0)
				//遍历找出超时的1400server
				gatServerInfoMap.Range(func(key string, value interface{}) bool {
					if _, ok := value.(*model.GatServerInfo); ! ok {
						logger.LOG_ERROR(fmt.Sprintf("类型错误,需要【*model.gatServerInfo】类型，类型为%T", value))
						return false
					}
					gatServerInfo := value.(*model.GatServerInfo)
					if (time.Since(times.Stamp2TimeWithFormat(gatServerInfo.KeepaliveTime, times.DateFormatLongNoSpan)).Seconds()) > KEEPALIVE_TIMEOUT {
						logger.LOG_WARN("ServerInfo time : ", gatServerInfo.KeepaliveTime)
						logger.LOG_WARN("time.Since : ", time.Since(times.Stamp2TimeWithFormat(gatServerInfo.KeepaliveTime, times.DateFormatLongNoSpan)).Seconds())
						timeOutKeys = append(timeOutKeys, gatServerInfo.ServerId)
					}
					return true
				})
				//删除已超时的服务列表
				for _, key := range timeOutKeys {
					logger.LOG_WARN("此1400server服务已超时、移除列表,服务id为：", key)
					gatServerInfoMap.Delete(key)
				}
				if gatServerInfoMap.Len() == 0 {
					logger.LOG_WARN("此视图库id的服务列表全部超时，视图库id为： ", key)
					delViewIds = append(delViewIds, key)
				}
				return true
			})
			for _, id := range delViewIds {
				logger.LOG_WARN("此视图库id的服务列表已被移除，视图库id为： ", id)
				cache.GetIns().GatServerInfos.Delete(id)
			}
		}
	}()
}

//寻找最佳1400server服务
func FindSerInfo(serverInfos *cache.GatServerInfoViewMap) *model.GatServerInfo {
	findSerInfo := &model.GatServerInfo{
		ByteRate1: math.MaxFloat64,
	}
	serverInfos.Range(func(key string, value interface{}) bool {
		serInfo := value.(*model.GatServerInfo)
		if CalculateWeight(serInfo) > CalculateWeight(findSerInfo) {
			return true
		}
		findSerInfo = serInfo
		return true
	})
	return findSerInfo
}

//权重：
//1.a   Math.min(心跳间隔 *120 / t,20) t:距上一次分配时间
//2.t    t < 心跳间隔  ? 0 : (t-心跳间隔) * 4) t:节点距上一次心跳时长
//3.c    c: 设备上报的最近一分钟每秒数据
//4.d    d: 接入带宽
func CalculateWeight(serInfo *model.GatServerInfo) float64 {
	//1
	a := math.Min(INTERVAL_KEEPALIVE_TIME*COEFFICIENT_ALLOCATE/(time.Since(times.Stamp2Time(serInfo.AllocateTime)).Seconds()), 20)
	logger.LOG_WARN("a =========>", a)
	var t float64
	//2
	if time.Since(times.Stamp2Time(serInfo.KeepaliveTime)).Seconds() < INTERVAL_KEEPALIVE_TIME {
		t = 0
	} else {
		t = (time.Since(times.Stamp2Time(serInfo.KeepaliveTime)).Seconds() - INTERVAL_KEEPALIVE_TIME) * COEFFICIENT_KEEPALIVE
	}
	logger.LOG_WARN("t =========>", t)
	//3
	var tps float64
	switch a := serInfo.ByteRate1 / serInfo.DataRate1; {
	case a > 500*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_500_KEY, COEFFICIENT_TPS_DATA500) * 100
	case a > 400*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_400_KEY, COEFFICIENT_TPS_DATA400) * 100
	case a > 300*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_300_KEY, COEFFICIENT_TPS_DATA300) * 100
	case a > 100*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_100_KEY, COEFFICIENT_TPS_DATA100) * 100
	case a > 10*1024 && a < 100*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_10_100_KEY, COEFFICIENT_TPS_DATA10_100) * 100
	case a < 10*1024:
		tps = serInfo.DataRate1 / context.GetFloat64Default(DATA_RATE_SIZE_0_10_KEY, COEFFICIENT_TPS_DATA0_10) * 100
	}
	logger.LOG_WARN("tps =========>", tps)
	//4
	network := serInfo.ByteRate1 / context.GetFloat64Default(COEFFICIENT_NETWORK_KEY, COEFFICIENT_NETWORK)
	logger.LOG_WARN("network =========>", network)
	weight := a + t + tps + network
	logger.LOG_WARN("【节点权重】 ", serInfo.ServerId, ": ", weight)
	return weight
}
